﻿using AMS.Services.DomainModels;
using OA.Infrastructure.Abstractions;
using Quartz;

namespace AMS.Services.Job;

[DisallowConcurrentExecution]
public class InitializeInfrastructure : IJob
{
    private readonly DbContext _ctx;

    public InitializeInfrastructure(DbContext context)
    {
        _ctx = context;
    }

    public Task Execute(IJobExecutionContext context)
    {
        TryMigrateDatabase();
        InitializeSystemData();

        return Task.CompletedTask;
    }

    public void TryMigrateDatabase()
    {
        var @new = _ctx.Database.EnsureCreated();

        if (@new)
        {
            var systemSettings = new SystemSettings
            {
                SendMessage = false
            };

            _ctx.Set<SystemSettings>().Add(systemSettings);

            #region 角色
            var sysAdminRole = new Role
            {
                Name = "系统管理员",
                RoleCode = Guid.NewGuid().ToString().Replace("-", string.Empty),
                Types = new List<string>() { "#" },
                ViewRoutes = new List<string>() { "#" }
            };

            var adminRole = new Role
            {
                Name = "管理员",
                RoleCode = Guid.NewGuid().ToString().Replace("-", string.Empty),
                Types = new List<string>() { "#", "~SystemSettings:UpdateAsync(UpdateModel)" },
                ViewRoutes = new List<string>() { "#", "~/log", "~/settings/system" }
            };

            var normalRole = new Role
            {
                Name = "普通用户",
                RoleCode = Guid.NewGuid().ToString().Replace("-", string.Empty),
                Types = new List<string>() {
                    "FixedAssetsConsuming:CreateAsync(CreateModel)", "FixedAssetsStorage:CreateAsync(CreateModel)", "FreeAssetsConsuming:CreateAsync(CreateModel)",
                    "FreeAssetsStorage:CreateAsync(CreateModel)"
                },
                ViewRoutes = new List<string>() { "/approval", "/fixed-assets/storage", "/fixed-assets/consuming", "/free-assets/storage", "/free-assets/consuming", "/fixed-assets/loss" }
            };

            var receptionRole = new Role
            {
                Name = "前台",
                RoleCode = Guid.NewGuid().ToString().Replace("-", string.Empty),
                Types = new List<string>() { "Approval:PassAsync(Int32)", "Approval:RejectAsync(Int32,String)" },
                ViewRoutes = new List<string>() { "/fixed-assets/storage", "/free-assets/storage" }
            };

            var purchaserRole = new Role
            {
                Name = "采购员",
                RoleCode = Guid.NewGuid().ToString().Replace("-", string.Empty),
                Types = new List<string>() { "Purchase:CreateAsync(CreateModel)" },
                ViewRoutes = new List<string>() { "/purchase" }
            };

            var repoManager = new Role
            {
                Name = "库存管理员",
                RoleCode = Guid.NewGuid().ToString().Replace("-", string.Empty),
                Types = new List<string>()
                {
                    "FixedAssetsStorage:CreateAsync(CreateModel)", "FixedAssetsRepo:UpdateAsync(Int32,UpdateModel)", "FreeAssetsStorage:CreateAsync(CreateModel)"
                },
                ViewRoutes = new List<string>() { "/fixed-assets/storage", "/free-assets/storage", "/fixed-assets/repo", "/free-assets/repo" }
            };

            _ctx.Set<Role>().AddRange(sysAdminRole, adminRole, normalRole, receptionRole, purchaserRole, repoManager);
            #endregion

            var sysAdmin = new User
            {
                Name = "admin",
                Account = "admin",
                JobNumber = string.Empty,
                UserId = "admin",
                Password = App.Encrypt("ap"),
                Roles = new HashSet<Role>() { sysAdminRole }
            };

            _ctx.Set<User>().Add(sysAdmin);

            if (App.ManagedByDocker)
            {
                var service = App.Services.GetRequiredService<IWeComService>();
                var depts = service.GetDepartmentsAsync().Result.Data;

                var userInsertList = new List<User>();

                foreach (var dept in depts)
                {
                    if (dept.Name is "HR" or "IT")
                    {
                        dept.Roles.Add(adminRole);
                        dept.Roles.Add(normalRole);
                    }
                    else
                    {
                        dept.Roles.Add(normalRole);
                    }

                    var users = service.GetDepartmentUsersAsync(dept).Result.Data.ToList();

                    foreach (var user in users)
                    {
                        user.Roles = new HashSet<Role>() { normalRole };

                        if (user.Department!.Name is "HR" or "IT")
                        {
                            user.Roles.Add(adminRole);
                        }
                    }

                    userInsertList.AddRange(users);

                    _ctx.Set<Department>().Add(dept);
                }

                _ctx.SaveChanges();

                _ctx.Set<User>().AddRange(userInsertList);

                var leadersDept = new List<Department>();

                foreach (var user in userInsertList.Where(x => x.IsLeader))
                {
                    var leadDept = _ctx.Set<Department>().First(x => x.Id == user.Department!.Id);
                    leadDept.Leader = user;
                    leadersDept.Add(leadDept);
                }

                foreach (var dept in depts.Where(x => x.Parent != null))
                {
                    dept.Parent = depts.First(x => x.Id == dept.Parent?.Id);

                    _ctx.Set<Department>().Update(dept);
                }

                _ctx.Set<Department>().UpdateRange(leadersDept);

                _ctx.SaveChanges();
            }
            else
            {
                #region 部门
                var testDept = new Department
                {
                    Name = "测试",
                    Roles = new HashSet<Role>() { normalRole }
                };

                var hrDept = new Department
                {
                    Name = "人力资源",
                    Roles = new HashSet<Role>() { normalRole }
                };

                var itDept = new Department
                {
                    Name = "信息技术",
                    Roles = new HashSet<Role>() { adminRole }
                };

                _ctx.Set<Department>().AddRange(testDept, hrDept, itDept);
                _ctx.SaveChanges();

                #endregion

                #region 用户                
                var ray = new User
                {
                    Name = "曾子墨",
                    Account = "8163",
                    JobNumber = "8163",
                    UserId = "8163",
                    Password = App.Encrypt("ap"),
                    Department = testDept
                };

                var banana = new User
                {
                    Name = "刘香姣",
                    Account = "8030",
                    JobNumber = "8030",
                    UserId = "8030",
                    IsLeader = true,
                    Password = App.Encrypt("ap"),
                    Department = hrDept,
                    Roles = new HashSet<Role>() { adminRole }
                };

                var sunny = new User
                {
                    Name = "宋沛沂",
                    Account = "8096",
                    JobNumber = "8096",
                    UserId = "8096",
                    IsLeader = true,
                    DirectLeader = banana,
                    Password = App.Encrypt("ap"),
                    Department = hrDept,
                    Roles = new HashSet<Role>() { receptionRole }
                };

                hrDept.Leader = banana;

                var hill = new User
                {
                    Name = "张细耳",
                    Account = "8006",
                    JobNumber = "8006",
                    UserId = "8006",
                    DirectLeader = sunny,
                    Password = App.Encrypt("ap"),
                    Department = itDept
                };

                var vico = new User
                {
                    Name = "高成锋",
                    Account = "8166",
                    JobNumber = "8166",
                    UserId = "8166",
                    Password = App.Encrypt("ap"),
                    Department = testDept,
                    Roles = new HashSet<Role>() { repoManager }
                };

                _ctx.Set<User>().AddRange(ray, sunny, hill, vico);
                _ctx.Set<Department>().Update(hrDept);
                #endregion

                _ctx.SaveChanges();
            }

            #region 初始化业务数据
            try
            {
                var sunny = _ctx.Set<User>().First(n => n.Account == "8096");
                var hill = _ctx.Set<User>().First(n => n.Account == "8006");
                var banana = _ctx.Set<User>().First(n => n.Account == "8030");

                var fixedAssetsStorageFlowConfig = new ApproverConfig
                {
                    Key = RegisteredApprovalFlows.FixedAssetsStorageApprovalFlowDefinition.Key,
                    Name = RegisteredApprovalFlows.FixedAssetsStorageApprovalFlowDefinition.BizName,
                    ApproverDetails = new HashSet<ApproverConfigDetail>()
                    {
                        new ApproverConfigDetail
                        {
                            Approver = hill,
                            Sort = 1
                        },
                        new ApproverConfigDetail
                        {
                            Approver = banana,
                            Sort = 2
                        }
                    }
                };

                var fixedAssetsConsumingFlowConfig = new ApproverConfig
                {
                    Key = RegisteredApprovalFlows.FixedAssetsConsumingApprovalFlowDefinition.Key,
                    Name = RegisteredApprovalFlows.FixedAssetsConsumingApprovalFlowDefinition.BizName,
                    ApproverDetails = new HashSet<ApproverConfigDetail>()
                    {
                        new ApproverConfigDetail
                        {
                            Approver = hill,
                            Sort = 1
                        }
                    }
                };

                var fixedAssetsReturnFlowConfig = new ApproverConfig
                {
                    Key = RegisteredApprovalFlows.FixedAssetsReturnApprovalFlowDefinition.Key,
                    Name = RegisteredApprovalFlows.FixedAssetsReturnApprovalFlowDefinition.BizName,
                    ApproverDetails = new HashSet<ApproverConfigDetail>()
                    {
                        new ApproverConfigDetail
                        {
                            Approver = hill,
                            Sort = 1
                        }
                    }
                };

                var freeAssetsStorageFlowConfig = new ApproverConfig
                {
                    Key = RegisteredApprovalFlows.FreeAssetsStorageApprovalFlowDefinition.Key,
                    Name = RegisteredApprovalFlows.FreeAssetsStorageApprovalFlowDefinition.BizName,
                    ApproverDetails = new HashSet<ApproverConfigDetail>()
                    {
                        new ApproverConfigDetail
                        {
                            Approver = sunny,
                            Sort = 1
                        }
                    }
                };

                var freeAssetsConsumingFlowConfig = new ApproverConfig
                {
                    Key = RegisteredApprovalFlows.FreeAssetsConsumingApprovalFlowDefinition.Key,
                    Name = RegisteredApprovalFlows.FreeAssetsConsumingApprovalFlowDefinition.BizName,
                    ApproverDetails = new HashSet<ApproverConfigDetail>()
                    {
                        new ApproverConfigDetail
                        {
                            Approver = sunny,
                            Sort = 1
                        }
                    }
                };

                var purchaseFlowConfig = new ApproverConfig
                {
                    Key = RegisteredApprovalFlows.PurchaseApprovalFlowDefinition.Key,
                    Name = RegisteredApprovalFlows.PurchaseApprovalFlowDefinition.BizName,
                    ApproverDetails = new HashSet<ApproverConfigDetail>()
                    {
                        new ApproverConfigDetail
                        {
                            Approver = sunny,
                            Sort = 1
                        },
                        new ApproverConfigDetail
                        {
                            Approver = banana,
                            Sort = 2
                        }
                    }
                };

                var lossFlowConfig = new ApproverConfig
                {
                    Key = RegisteredApprovalFlows.LossApprovalFlowDefinition.Key,
                    Name = RegisteredApprovalFlows.LossApprovalFlowDefinition.BizName,
                    ApproverDetails = new HashSet<ApproverConfigDetail>()
                    {
                        new ApproverConfigDetail
                        {
                            Approver = hill,
                            Sort = 1
                        }
                    }
                };

                _ctx.Set<ApproverConfig>().AddRange(
                    fixedAssetsStorageFlowConfig,
                    fixedAssetsConsumingFlowConfig,
                    fixedAssetsReturnFlowConfig,
                    freeAssetsStorageFlowConfig,
                    freeAssetsConsumingFlowConfig,
                    purchaseFlowConfig,
                    lossFlowConfig);

                _ctx.SaveChanges();
            }
            catch (Exception)
            {
                Console.WriteLine("数据库实例未初始化成功");
            }

            #endregion
        }
    }

    private void InitializeSystemData()
    {
        App.AdminRoleCodes = _ctx.Set<Role>()
            .Select(n => new { n.Name, n.RoleCode })
            .Where(n => n.Name == "管理员" || n.Name == "系统管理员")
            .Select(n => n.RoleCode)
            .ToArray();
    }
}